package de.akabahn.ebd.control;

import static android.widget.Toast.LENGTH_LONG;
import static android.widget.Toast.LENGTH_SHORT;
import static de.akabahn.ebd.control.auth.AccessEnum.ACTIVE;
import static de.akabahn.ebd.control.auth.AccessEnum.COMMON;
import static de.akabahn.ebd.control.auth.AccessEnum.RESTRICTED;
import static de.akabahn.ebd.control.auth.AccessEnum.TECHNICIAN;
import static de.akabahn.ebd.control.common.Config.TFZ_VMAX;
import static de.akabahn.ebd.control.common.Config.TFZ_VMAX_SHUNTING;
import static de.akabahn.ebd.fst.Tfz.Mode.AUTO;
import static de.akabahn.ebd.fst.Tfz.Mode.MANUAL;
import static de.akabahn.ebd.fst.Tfz.Mode.MULTITRACTION;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Observer;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.graphics.Color;
import android.os.Bundle;
import android.text.InputType;
import android.text.TextUtils;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ToggleButton;
import de.akabahn.ebd.comm.Util;
import de.akabahn.ebd.control.comm.TfzInfo;
import de.akabahn.ebd.control.comm.TfzInfoProvider;
import de.akabahn.ebd.control.common.Config;
import de.akabahn.ebd.control.data.StaticDataStorage;
import de.akabahn.ebd.fst.FahrSteuerungAdapter;
import de.akabahn.ebd.fst.FahrSteuerungAdapterFactory;
import de.akabahn.ebd.fst.Tfz;
import de.akabahn.ebd.fst.Tfz.Direction;
import de.akabahn.ebd.fst.Tfz.Mode;

/**
 * @author Peter Eimann
 */
public class EBD_HandreglerActivity extends EBD_BaseActivity implements OnClickListener, OnSeekBarChangeListener,
		OnItemSelectedListener, OnTouchListener {

	private final static String[] EMPTY_TEXT = new String[] {"", ""};
	private final static int[] FUNCTION_BUTTONS = {R.id.handregler_buttonF0, R.id.handregler_buttonF1, 
			R.id.handregler_buttonF2, R.id.handregler_buttonF3, R.id.handregler_buttonF4};

	private FahrSteuerungAdapter fahrsteuerungAdapter;
	private TfzInfoProvider tfzInfoProvider;

	private EditText vaInfoField;
	private SeekBar speedBar;
	private Spinner tfzSpinner;
	private Spinner bhfSpinner;
	private Spinner gleisSpinner;
	
	private TfzInfo selectedTfzInfo;
	private String selectedTfzNr;
	private String selectedTfzZn;
	private int selectedTfzFst;
	private Mode selectedTfzMode;
	private boolean tfzAufHandregler;
	private boolean tfzControlledByApp;

	private boolean suppressSpeedChange;
	private boolean suppressTfzChange;
	private boolean menuClicked;
	private boolean shuntMode;
	private boolean speedControl;
	private boolean abvEnabled;

	private Thread tfzInfoThread;
	private boolean loopStarted;
	private long loopCounter;
	private Tfz tfzInfo;
	private String[] tfzInfoText;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.handregler);
	}

	@Override
	protected void onStart() {
		super.onStart();

		tfzControlledByApp = false;
		suppressTfzChange = true;
		suppressSpeedChange = true;
		shuntMode = true;
		speedControl = true;
		selectedTfzInfo = null;
		selectedTfzNr = null;
		selectedTfzZn = null;
		selectedTfzFst = 0;
		if (speedBar != null) {
			speedBar.setProgress(0);
		}

		try {
			initializeUser();
			initializeView();
			initializeFahrSteuerung();
			initializeButtons();
			initializeSeekBar();
			initializeSpinners();
			enableButtons(false);
			findTextView(R.id.handregler_hndr_heading).setTextColor(Color.GREEN);
			loopStarted = true;
		} catch (Exception e) {
			findTextView(R.id.handregler_hndr_heading).setTextColor(Color.RED);
			handleException(e);
		}

		initializeInfoThread();
		tfzInfoThread.start();

		getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
	}

	@Override
	protected void onStop() {
		super.onStop();
		loopStarted = false;

		try {
			if (fahrsteuerungAdapter.isStarted()) {
				if (selectedTfzNr != null && tfzControlledByApp && selectedTfzMode == MANUAL && !tfzAufHandregler) {
					if (abvEnabled) {
						executeFunction(selectedTfzInfo.getFuncAbv(), true);
						abvEnabled = false;
					}
					fahrsteuerungAdapter.stop(selectedTfzNr);
				}
				fahrsteuerungAdapter.stop();
			}
		} catch (Exception e) {
			handleException(e);
		}

		tfzControlledByApp = false;
		tfzAufHandregler = false;
		suppressSpeedChange = false;
		suppressTfzChange = false;
		selectedTfzInfo = null;
		selectedTfzNr = null;
		selectedTfzZn = null;
		selectedTfzFst = 0;
		if (speedBar != null) {
			speedBar.setProgress(0);
		}

		if (tfzInfoThread != null) {
			try {
				tfzInfoThread.join(5000);
				tfzInfoThread = null;
			} catch (InterruptedException e) {
			}
		}
		getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
	}

	@Override
	public void onClick(View v) {
		try {
			switch (v.getId()) {
				case R.id.handregler_chooseTfzBtn:
					executeChooseTfz();
					break;
				case R.id.handregler_stopTfzBtn:
					if (selectedTfzMode == AUTO) {
						AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
						alertDialogBuilder.setTitle(getResources().getString(R.string.handregler_toManual_title));
						alertDialogBuilder.setMessage(getResources().getString(R.string.handregler_toManual_message));
						alertDialogBuilder.setCancelable(false);
						alertDialogBuilder.setPositiveButton(getResources().getString(R.string.handregler_label_yes), 
							new DialogInterface.OnClickListener() {
								public void onClick(DialogInterface dialog, int id) {
									dialog.cancel();
									executeStopTfz();
								}
							});
						alertDialogBuilder.setNegativeButton(getResources().getString(R.string.handregler_label_no),
							new DialogInterface.OnClickListener() {
								public void onClick(DialogInterface dialog, int id) {
									dialog.cancel();
								}
							});

						AlertDialog alertDialog = alertDialogBuilder.create();
						alertDialog.show();
					} else {
						executeStopTfz();
					}
					break;
				case R.id.handregler_richTfzBtn:
					if (selectedTfzMode == AUTO) {
						AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
						alertDialogBuilder.setTitle(getResources().getString(R.string.handregler_doRich_title));
						alertDialogBuilder.setMessage(getResources().getString(R.string.handregler_doRich_message));
						alertDialogBuilder.setCancelable(false);
						alertDialogBuilder.setPositiveButton(getResources().getString(R.string.handregler_label_yes), 
							new DialogInterface.OnClickListener() {
								public void onClick(DialogInterface dialog, int id) {
									dialog.cancel();
									executeRichTfz();
								}
							});
						alertDialogBuilder.setNegativeButton(getResources().getString(R.string.handregler_label_no),
							new DialogInterface.OnClickListener() {
								public void onClick(DialogInterface dialog, int id) {
									dialog.cancel();
								}
							});

						AlertDialog alertDialog = alertDialogBuilder.create();
						alertDialog.show();
					} else {
						executeRichTfz();
					}
					break;
				case R.id.handregler_einbuchTfzBtn:
					executeEinbuchTfz();
					break;
				case R.id.handregler_reloadTfzBtn:
					executeReloadTfz();
					break;
				case R.id.handregler_buttonF0:
					if (selectedTfzInfo == null || 
						(selectedTfzInfo.getFuncPfeifen() != 0 && selectedTfzInfo.getFuncTueren() != 0)) {
						executeFunction(0, null);
					}
					break;
				case R.id.handregler_buttonF1:
					if (selectedTfzInfo == null || 
						(selectedTfzInfo.getFuncPfeifen() != 1 && selectedTfzInfo.getFuncTueren() != 1)) {
						executeFunction(1, null);
					}
					break;
				case R.id.handregler_buttonF2:
					if (selectedTfzInfo == null || 
						(selectedTfzInfo.getFuncPfeifen() != 2 && selectedTfzInfo.getFuncTueren() != 2)) {
						executeFunction(2, null);
					}
					break;
				case R.id.handregler_buttonF3:
					if (selectedTfzInfo == null || 
						(selectedTfzInfo.getFuncPfeifen() != 3 && selectedTfzInfo.getFuncTueren() != 3)) {
						executeFunction(3, null);
					}
					break;
				case R.id.handregler_buttonF4:
					if (selectedTfzInfo == null || 
						(selectedTfzInfo.getFuncPfeifen() != 4 && selectedTfzInfo.getFuncTueren() != 4)) {
						executeFunction(4, null);
					}
					break;
				case R.id.handregler_deleteTfzBtn:
					executeDeleteTfz();
			}
			findTextView(R.id.handregler_hndr_heading).setTextColor(Color.GREEN);
		} catch (Exception e) {
			findTextView(R.id.handregler_hndr_heading).setTextColor(Color.RED);
			handleException(e);
		}
	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		switch (v.getId()) {
			case R.id.handregler_buttonF0:
				if (selectedTfzInfo != null) {
					if (selectedTfzInfo.getFuncPfeifen() == 0) {
						checkFunctionButtonTouchAction(v, event, 0);
						return true;
					} else if (selectedTfzInfo.getFuncTueren() == 0) {
						checkFunctionButtonTouchAction(v, event, 0);
						return true;
					}
				}
				break;
			case R.id.handregler_buttonF1:
				if (selectedTfzInfo != null) {
					if (selectedTfzInfo.getFuncPfeifen() == 1) {
						checkFunctionButtonTouchAction(v, event, 1);
						return true;
					} else if (selectedTfzInfo.getFuncTueren() == 1) {
						checkFunctionButtonTouchAction(v, event, 1);
						return true;
					}
				}
				break;
			case R.id.handregler_buttonF2:
				if (selectedTfzInfo != null) {
					if (selectedTfzInfo.getFuncPfeifen() == 2) {
						checkFunctionButtonTouchAction(v, event, 2);
						return true;
					} else if (selectedTfzInfo.getFuncTueren() == 2) {
						checkFunctionButtonTouchAction(v, event, 2);
						return true;
					}
				}
				break;
			case R.id.handregler_buttonF3:
				if (selectedTfzInfo != null) {
					if (selectedTfzInfo.getFuncPfeifen() == 3) {
						checkFunctionButtonTouchAction(v, event, 3);
						return true;
					} else if (selectedTfzInfo.getFuncTueren() == 3) {
						checkFunctionButtonTouchAction(v, event, 3);
						return true;
					}
				}
				break;
			case R.id.handregler_buttonF4:
				if (selectedTfzInfo != null) {
					if (selectedTfzInfo.getFuncPfeifen() == 4) {
						checkFunctionButtonTouchAction(v, event, 4);
						return true;
					} else if (selectedTfzInfo.getFuncTueren() == 4) {
						checkFunctionButtonTouchAction(v, event, 4);
						return true;
					}
				}
				break;
		}

		return false;
	}

	@Override
	public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
		if (selectedTfzInfo != null && speedControl) {
			vaInfoField.setText(Integer.toString(progress * 5) + " " + getResources().getString(R.string.handregler_kmh));
		} else {
			vaInfoField.setText(Integer.toString(progress));
		}
	}

	@Override
	public void onStartTrackingTouch(SeekBar seekBar) {
		// Nothing to do
	}

	@Override
	public void onStopTrackingTouch(SeekBar seekBar) {
		if (selectedTfzInfo != null && speedControl) {
			vaInfoField.setText(Integer.toString(seekBar.getProgress() * 5) + " " + getResources().getString(R.string.handregler_kmh));
		} else {
			vaInfoField.setText(Integer.toString(seekBar.getProgress()));
		}
	}

	@Override
	public void onItemSelected(AdapterView<?> parent, View view, int pos, long id) {
		if (pos >= 0) {
			if (parent == findViewById(R.id.handregler_stdortBhfSpinner)) {
				String[] gleise = StaticDataStorage.getInstance().getGleise(parent.getItemAtPosition(pos).toString());
				setSpinnerValues(R.id.handregler_stdortGleisSpinner, gleise);
			} else if (parent == findViewById(R.id.handregler_tfzSpinner)) {
				if (!suppressTfzChange) {
					findViewById(R.id.handregler_chooseTfzBtn).setEnabled(true);
					if (selectedTfzNr != null) {
						findTextView(R.id.handregler_chooseTfzLabel).setTextColor(Color.RED);
					}
				}
				suppressTfzChange = false;
			}
		}
	}

	@Override
	public void onNothingSelected(AdapterView<?> parent) {
	}

	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		menu.findItem(R.id.menu_fst).setVisible(role != RESTRICTED && selectedTfzMode != MULTITRACTION);
		menu.findItem(R.id.menu_debugdata).setVisible(role == ACTIVE || role == TECHNICIAN);
		menu.findItem(R.id.menu_speed_ctrl).setVisible(role == ACTIVE || role == TECHNICIAN);
		menu.findItem(R.id.menu_shuntmode).setVisible(role == ACTIVE || role == TECHNICIAN);
		menu.findItem(R.id.menu_manageuser).setVisible(role == TECHNICIAN);

		if (role != RESTRICTED) {
			menu.findItem(R.id.menu_fst_cont).setVisible(role == ACTIVE || role == TECHNICIAN);
			menu.findItem(R.id.menu_fst_endw).setVisible(role == ACTIVE || role == TECHNICIAN);
			menu.findItem(R.id.menu_fst_hndr).setVisible(role == ACTIVE || role == TECHNICIAN);
			menu.findItem(R.id.menu_fst_hold).setVisible(role == ACTIVE || role == TECHNICIAN);
			menu.findItem(R.id.menu_fst_init).setVisible(role == ACTIVE || role == TECHNICIAN);
			menu.findItem(R.id.menu_fst_term).setVisible(role == ACTIVE || role == TECHNICIAN);
			menu.findItem(R.id.menu_fst_umk).setVisible(role == ACTIVE || role == TECHNICIAN);
			menu.findItem(R.id.menu_fst_wait).setVisible(role == ACTIVE || role == TECHNICIAN);

			menu.findItem(R.id.menu_fst_bef2).setEnabled(selectedTfzNr != null && tfzInfo.getMode() == AUTO);
			menu.findItem(R.id.menu_fst_cont).setEnabled(selectedTfzNr != null && tfzInfo.getMode() == AUTO && tfzInfo.isHold());
			menu.findItem(R.id.menu_fst_endw).setEnabled(selectedTfzNr != null && tfzInfo.getMode() == AUTO && tfzInfo.isWait());
			menu.findItem(R.id.menu_fst_fertig).setEnabled(selectedTfzNr != null && !tfzInfo.isReady());
			menu.findItem(R.id.menu_fst_zn).setEnabled(selectedTfzNr != null && tfzInfo.getMode() == AUTO);
			menu.findItem(R.id.menu_fst_hndr).setEnabled(selectedTfzNr != null && tfzInfo.getMode() == MANUAL);
			menu.findItem(R.id.menu_fst_hold).setEnabled(selectedTfzNr != null && tfzInfo.getMode() == AUTO && !tfzInfo.isHold());
			menu.findItem(R.id.menu_fst_mtm).setEnabled(selectedTfzNr != null && tfzInfo.isMasterTfz());
			menu.findItem(R.id.menu_fst_mtp).setEnabled(selectedTfzNr != null && tfzSpinner.getAdapter().getCount() > 1);
			menu.findItem(R.id.menu_fst_term).setEnabled(selectedTfzNr != null && tfzInfo.getSpeed() == 0);
			menu.findItem(R.id.menu_fst_umk).setEnabled(selectedTfzNr != null);
			menu.findItem(R.id.menu_fst_wait).setEnabled(selectedTfzNr != null && tfzInfo.getMode() == AUTO && !tfzInfo.isWait());
			menu.findItem(R.id.menu_speed_ctrl).setEnabled(speedBar != null && speedBar.getProgress() == 0);
			menu.findItem(R.id.menu_shuntmode).setEnabled(speedBar != null && speedBar.getProgress() == 0);
		}

		return true;
	}

	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
			case R.id.menu_speed_ctrl:
				item.setChecked(!item.isChecked());
				speedControl = item.isChecked();
				prepareSpeedBarAndLabels();
				break;
			case R.id.menu_shuntmode:
				item.setChecked(!item.isChecked());
				shuntMode = item.isChecked();
				prepareSpeedBarAndLabels();
				break;
			case R.id.menu_fst_bef2:
				executeBef2Tfz();
				break;
			case R.id.menu_fst_cont:
				executeContTfz();
				break;
			case R.id.menu_fst_endw:
				executeEndwTfz();
				break;
			case R.id.menu_fst_fertig:
				executeFertigTfz();
				break;
			case R.id.menu_fst_zn:
				performZnTfz();
				break;
			case R.id.menu_fst_hndr:
				performHndrTfz();
				break;
			case R.id.menu_fst_hold:
				executeHoldTfz();
				break;
			case R.id.menu_fst_init:
				performInitTfz();
				break;
			case R.id.menu_fst_mtm:
				performMtmTfz();
				break;
			case R.id.menu_fst_mtp:
				performMtpTfz();
				break;
			case R.id.menu_fst_term:
				performTermTfz();
				break;
			case R.id.menu_fst_umk:
				performUmkTfz();
				break;
			case R.id.menu_fst_wait:
				executeWaitTfz();
				break;
		}

		return super.onOptionsItemSelected(item);
	}

	@Override
	public boolean onKeyDown(int keyCode, KeyEvent event) {
		switch (keyCode) {
			case KeyEvent.KEYCODE_MENU:
				if (!menuClicked) {
					menuClicked = true;
					invalidateOptionsMenu();
				}
		}

		return super.onKeyDown(keyCode, event);
	}

	private String[] getTfzArrayForMultitraction(boolean add) {
		List<String> availTfzList = new ArrayList<String>();
		List<Tfz> allTfzList = fahrsteuerungAdapter.inf();

		for (Tfz tfz : allTfzList) {
			if ((add && tfz.getMode() != MULTITRACTION && !selectedTfzNr.equals(tfz.getAddress()))
					|| (!add && tfz.getMode() == MULTITRACTION)) {
				availTfzList.add(tfz.getAddress());
			}
		}
		Collections.sort(availTfzList, new Comparator<String>() {
			@Override
			public int compare(String o1, String o2) {
				return o1.compareTo(o2);
			}
		});

		return availTfzList.toArray(new String[]{});
	}

	private void initializeFahrSteuerung() {
		boolean demoMode = (role == RESTRICTED || role == COMMON)
				? Config.DEMO_MODE
				: preferences.getBoolean("pref_key_demo_mode_flag", false);
		boolean controlled = (role == RESTRICTED || role == COMMON)
				? Config.FST_CONTROLLED
				: preferences.getBoolean("pref_key_fst_control_flag", false);
		String fstServer = (role == RESTRICTED || role == COMMON)
				? Config.FST_SERVER_NAME
				: preferences.getString("pref_key_fst_server", "");
		int fstPort = (role == RESTRICTED || role == COMMON)
				? Config.FST_SERVER_PORT
				: Integer.parseInt(preferences.getString("pref_key_fst_port", ""));
		String fstCtrlServer = (role == RESTRICTED || role == COMMON)
				? Config.FST_CONTROL_SERVER_NAME
				: preferences.getString("pref_key_fstctrl_server", "");
		int fstCtrlPort = (role == RESTRICTED || role == COMMON)
				? Config.FST_CONTROL_SERVER_PORT 
				: Integer.parseInt(preferences.getString("pref_key_fstctrl_port", ""));

		if (demoMode) {
			fahrsteuerungAdapter = FahrSteuerungAdapterFactory.getTestImplementation(false, (Observer[])null);
			tfzInfoProvider = TfzInfoProvider.getInstance(null, 0);
		} else {
			if (controlled) {
				fahrsteuerungAdapter = 
						FahrSteuerungAdapterFactory.getControlledImplementation(
								fstServer,
								fstPort,
								fstCtrlServer,
								fstCtrlPort,
								(Observer[])null);
				tfzInfoProvider = TfzInfoProvider.getInstance(fstCtrlServer, fstCtrlPort);
			} else {
				fahrsteuerungAdapter = 
						FahrSteuerungAdapterFactory.getUncontrolledImplementation(
								fstServer,
								fstPort,
								(Observer[])null);
				tfzInfoProvider = TfzInfoProvider.getInstance(null, 0);
			}
		}

		if (demoMode) {
			showText(getResources().getString(R.string.control_demoMode), LENGTH_SHORT);
		} else if (!controlled) {
			showText(getResources().getString(R.string.control_uncontrolled), LENGTH_SHORT);
		}

		fahrsteuerungAdapter.start();
	}

	private void initializeUser() {
		findTextView(R.id.handregler_userInfo).setText(getResources().getString(R.string.userInfo, userName, role));
	}

	private void initializeButtons() {
		findViewById(R.id.handregler_tfzVAInfoEdit).setEnabled(false);
		findViewById(R.id.handregler_tfzVAInfoEdit).setFocusable(false);

		findViewById(R.id.handregler_chooseTfzBtn).setOnClickListener(this);
		findViewById(R.id.handregler_stopTfzBtn).setOnClickListener(this);
		findViewById(R.id.handregler_richTfzBtn).setOnClickListener(this);
		findViewById(R.id.handregler_einbuchTfzBtn).setOnClickListener(this);
		findViewById(R.id.handregler_reloadTfzBtn).setOnClickListener(this);
		findViewById(R.id.handregler_buttonF0).setOnClickListener(this);
		findViewById(R.id.handregler_buttonF1).setOnClickListener(this);
		findViewById(R.id.handregler_buttonF2).setOnClickListener(this);
		findViewById(R.id.handregler_buttonF3).setOnClickListener(this);
		findViewById(R.id.handregler_buttonF4).setOnClickListener(this);
		findViewById(R.id.handregler_deleteTfzBtn).setOnClickListener(this);

		findViewById(R.id.handregler_buttonF0).setOnTouchListener(this);
		findViewById(R.id.handregler_buttonF1).setOnTouchListener(this);
		findViewById(R.id.handregler_buttonF2).setOnTouchListener(this);
		findViewById(R.id.handregler_buttonF3).setOnTouchListener(this);
		findViewById(R.id.handregler_buttonF4).setOnTouchListener(this);

		findViewById(R.id.handregler_chooseTfzBtn).setEnabled(true);
		findViewById(R.id.handregler_deleteTfzBtn).setEnabled(false);
	}

	private void initializeSeekBar() {
		int maxFst = role.equals(RESTRICTED) || role.equals(COMMON)
				? Config.SEEKBAR_FST_MAX
				: Integer.parseInt(preferences.getString("pref_key_num_fst", ""));

		vaInfoField = (EditText)findViewById(R.id.handregler_tfzVAInfoEdit);
		vaInfoField.setText("0");

		speedBar = (SeekBar)findViewById(R.id.handregler_tfzSeekBar);
		speedBar.setMax(maxFst);
		speedBar.setOnSeekBarChangeListener(this);
		findTextView(R.id.tfzSeekBarMiddleValue).setText("");
		findTextView(R.id.tfzSeekBarMaxValue).setText("");
	}

	@SuppressWarnings("unchecked")
	private void initializeSpinners() {
		loadAvailableTFZ();
		loadAvailableBhf();

		bhfSpinner = (Spinner)findViewById(R.id.handregler_stdortBhfSpinner);
		bhfSpinner.setOnItemSelectedListener(this);
		bhfSpinner.setEnabled(false);

		gleisSpinner = (Spinner)findViewById(R.id.handregler_stdortGleisSpinner);
		gleisSpinner.setEnabled(false);

		tfzSpinner = (Spinner)findViewById(R.id.handregler_tfzSpinner);
		tfzSpinner.setOnItemSelectedListener(this);

		if (bahnhof != null) {
			bhfSpinner.setSelection(((ArrayAdapter<CharSequence>)bhfSpinner.getAdapter()).getPosition(bahnhof));
		}
	}

	private void initializeView() {
		switch (role) {
			case RESTRICTED:
				findViewById(R.id.handregler_buttonF0).setVisibility(View.GONE);
				findViewById(R.id.handregler_buttonF1).setVisibility(View.GONE);
				findViewById(R.id.handregler_buttonF2).setVisibility(View.GONE);
				findViewById(R.id.handregler_buttonF3).setVisibility(View.GONE);
				findViewById(R.id.handregler_buttonF4).setVisibility(View.GONE);
				findViewById(R.id.handregler_hndr_ruler).setVisibility(View.GONE);
				findViewById(R.id.handregler_einbuch_wrapper).setVisibility(View.GONE);
				findViewById(R.id.handregler_tfzInfoLabel).setVisibility(View.GONE);
				findViewById(R.id.handregler_tfzInfoLabel2).setVisibility(View.GONE);
				break;
			case COMMON:
				findViewById(R.id.handregler_buttonF0).setVisibility(View.GONE);
				findViewById(R.id.handregler_buttonF1).setVisibility(View.GONE);
				findViewById(R.id.handregler_buttonF2).setVisibility(View.GONE);
				findViewById(R.id.handregler_buttonF3).setVisibility(View.GONE);
				findViewById(R.id.handregler_buttonF4).setVisibility(View.GONE);
				findViewById(R.id.handregler_hndr_ruler).setVisibility(View.VISIBLE);
				findViewById(R.id.handregler_einbuch_wrapper).setVisibility(View.VISIBLE);
				findViewById(R.id.handregler_tfzInfoLabel).setVisibility(View.GONE);
				findViewById(R.id.handregler_tfzInfoLabel2).setVisibility(View.GONE);
				break;
			default:
				findViewById(R.id.handregler_buttonF0).setVisibility(View.VISIBLE);
				findViewById(R.id.handregler_buttonF1).setVisibility(View.VISIBLE);
				findViewById(R.id.handregler_buttonF2).setVisibility(View.VISIBLE);
				findViewById(R.id.handregler_buttonF3).setVisibility(View.VISIBLE);
				findViewById(R.id.handregler_buttonF4).setVisibility(View.VISIBLE);
				findViewById(R.id.handregler_hndr_ruler).setVisibility(View.VISIBLE);
				findViewById(R.id.handregler_einbuch_wrapper).setVisibility(View.VISIBLE);
				findViewById(R.id.handregler_tfzInfoLabel).setVisibility(View.VISIBLE);
				findViewById(R.id.handregler_tfzInfoLabel2).setVisibility(View.VISIBLE);
		}
	}

	private void initializeInfoThread() {
		tfzInfoThread = new Thread(new Runnable() {
			@Override
			public void run() {
				while (loopStarted) {
					tfzInfoText = EMPTY_TEXT;
					loopCounter++;

					if (loopCounter % 2 == 0 && selectedTfzNr != null) {
						List<Tfz> tfzList = fahrsteuerungAdapter.inf(selectedTfzNr);
						if (!tfzList.isEmpty()) {
							tfzInfo = tfzList.get(0);
							tfzInfoText = tfzInfo.prettyPrint().split("\\n");
						}
						selectedTfzZn = (selectedTfzMode == AUTO) ? fahrsteuerungAdapter.zn(selectedTfzNr) : null;
					}

					if (speedBar.getProgress() != selectedTfzFst) {
						selectedTfzFst = speedBar.getProgress();
						if (!suppressSpeedChange) {
							try {
								if (!abvEnabled && selectedTfzInfo != null && selectedTfzInfo.getFuncAbv() != -1) {
									executeFunction(selectedTfzInfo.getFuncAbv(), false);
									abvEnabled = true;
								}
								if (selectedTfzInfo != null && speedControl) {
									fahrsteuerungAdapter.go(selectedTfzNr, selectedTfzInfo.getSpeedList().get(selectedTfzFst));
								} else {
									fahrsteuerungAdapter.go(selectedTfzNr, selectedTfzFst);
								}
								tfzControlledByApp = true;
								tfzAufHandregler = false;
							} catch (Exception e) {
								runOnUiThread(new Runnable() {
									public void run() {
										findTextView(R.id.handregler_hndr_heading).setTextColor(Color.RED);
									}
								});
								handleException(e);
							}
						}
						suppressSpeedChange = false;
					}

					runOnUiThread(new Runnable() {
						public void run() {
							int dirResId = 0;

							if (loopCounter % 2 == 0) {
								findTextView(R.id.handregler_tfzInfoLabel).setText(tfzInfoText[0]);
								findTextView(R.id.handregler_tfzInfoLabel2).setText(tfzInfoText[1]);
								for (int index = 0; index < FUNCTION_BUTTONS.length; index++) {
									setFunctionButtonColor(index);
								}
								if (selectedTfzNr != null) {
									if (selectedTfzZn != null) {
										findTextView(R.id.handregler_chooseTfzLabel).setText(
												getResources().getString(R.string.handregler_selectedTfzWithZn, selectedTfzNr, selectedTfzZn));
									} else {
										findTextView(R.id.handregler_chooseTfzLabel).setText(
												getResources().getString(R.string.handregler_selectedTfz, selectedTfzNr));
									}

									if (tfzInfo.getDirection() == Direction.ARROW) {
										dirResId = !tfzInfo.isReverse() ? R.string.handregler_richTfzPfeil : R.string.handregler_richTfzGegen;
									} else if (tfzInfo.getDirection() == Direction.REVERSE) {
										dirResId = !tfzInfo.isReverse() ? R.string.handregler_richTfzGegen : R.string.handregler_richTfzPfeil;
									} else {
										dirResId = R.string.handregler_richTfz;
									}
									((Button)findViewById(R.id.handregler_richTfzBtn)).setText(getResources().getString(dirResId));
								}
							}
							findTextView(R.id.handregler_hndr_left).setTextColor(loopCounter % 4 < 2 ? Color.GREEN : Color.BLACK);
							findTextView(R.id.handregler_hndr_right).setTextColor(loopCounter % 4 < 2 ? Color.GREEN : Color.BLACK);
						}
					});

					Util.sleep(500);
				}
			}
		});
	}

	private void loadAvailableBhf() {
		List<String> bahnhoefe = StaticDataStorage.getInstance().getBahnhoefe();
		String[] gleise = StaticDataStorage.getInstance().getGleise(bahnhof != null ? bahnhof : StaticDataStorage.ZDH);

		if (role == RESTRICTED || role == COMMON) {
			bahnhoefe.retainAll(Arrays.asList(new String[]{bahnhof}));
		} else {
			Collections.sort(bahnhoefe);
		}
		setSpinnerValues(R.id.handregler_stdortBhfSpinner, bahnhoefe.toArray(new String[]{}));
		setSpinnerValues(R.id.handregler_stdortGleisSpinner, gleise);
	}

	private void loadAvailableTFZ() {
		List<Tfz> allTfzList = new ArrayList<Tfz>();
		List<String> availTfzList = new ArrayList<String>();
		final String label = getResources().getString(R.string.handregler_tfznr_label);

		allTfzList = fahrsteuerungAdapter.inf();

		if (allTfzList.isEmpty()) {
			availTfzList.add("-");
		} else {
			availTfzList.add(label);
			for (Tfz tfz : allTfzList) {
				if (role != RESTRICTED || tfz.getLocation().startsWith(bahnhof.substring(1, 3)) ||
						(tfz.getMode().equals(MANUAL) && tfz.getSpeed() == 0)) {
					availTfzList.add(tfz.getAddress());
				}
			}
			Collections.sort(availTfzList, new Comparator<String>() {
				@Override
				public int compare(String o1, String o2) {
					if (label.equals(o1)) {
						return -1;
					} else if (label.equals(o2)) {
						return 1;
					} else {
						return o1.compareTo(o2);
					}
				}
			});
		}

		setSpinnerValues(R.id.handregler_tfzSpinner, availTfzList.toArray(new String[]{}));
	}

	private void performHndrTfz() {
		final Spinner spinner = new Spinner(this);
		ArrayAdapter<String> adapter = new ArrayAdapter<String>(
			this, android.R.layout.simple_spinner_item, getResources().getStringArray(R.array.handregler));
		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		spinner.setAdapter(adapter);

		AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
		alertDialogBuilder.setTitle(getResources().getString(R.string.handregler_hndr_title));
		alertDialogBuilder.setMessage(getResources().getString(R.string.handregler_hndr_message, selectedTfzNr));
		alertDialogBuilder.setCancelable(false);
		alertDialogBuilder.setView(spinner);
		alertDialogBuilder.setPositiveButton(getResources().getString(R.string.handregler_label_ok), 
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
					executeHndrTfz(spinner.getSelectedItem().toString());
				}
			});
		alertDialogBuilder.setNegativeButton(getResources().getString(R.string.handregler_label_cancel),
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
				}
			});

		AlertDialog alertDialog = alertDialogBuilder.create();
		alertDialog.show();
	}

	private void performInitTfz() {
		final EditText input = new EditText(this);
		input.setHint(R.string.handregler_tfznr_label);
		input.setInputType(InputType.TYPE_CLASS_NUMBER);

		AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
		alertDialogBuilder.setTitle(getResources().getString(R.string.handregler_init_title));
		alertDialogBuilder.setMessage(getResources().getString(R.string.handregler_init_message));
		alertDialogBuilder.setCancelable(false);
		alertDialogBuilder.setView(input);
		alertDialogBuilder.setPositiveButton(getResources().getString(R.string.handregler_label_ok), 
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
					executeInitTfz(input.getText().toString());
				}
			});
		alertDialogBuilder.setNegativeButton(getResources().getString(R.string.handregler_label_cancel),
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
				}
			});

		AlertDialog alertDialog = alertDialogBuilder.create();
		alertDialog.show();
	}

	private void performZnTfz() {
		final EditText input = new EditText(this);
		input.setHint(R.string.handregler_zugnr_label);
		input.setInputType(InputType.TYPE_CLASS_NUMBER);

		AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
		alertDialogBuilder.setTitle(getResources().getString(R.string.handregler_zn_title));
		alertDialogBuilder.setMessage(getResources().getString(R.string.handregler_zn_message, selectedTfzNr));
		alertDialogBuilder.setCancelable(false);
		alertDialogBuilder.setView(input);
		alertDialogBuilder.setPositiveButton(getResources().getString(R.string.handregler_label_ok), 
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
					executeZnTfz(input.getText().toString());
				}
			});
		alertDialogBuilder.setNegativeButton(getResources().getString(R.string.handregler_label_cancel),
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
				}
			});

		AlertDialog alertDialog = alertDialogBuilder.create();
		alertDialog.show();
	}

	private void performMtmTfz() {
		final Spinner spinner = new Spinner(this);
		ArrayAdapter<String> adapter = new ArrayAdapter<String>(
			this, android.R.layout.simple_spinner_item, getTfzArrayForMultitraction(false));
		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		spinner.setAdapter(adapter);

		AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
		alertDialogBuilder.setTitle(getResources().getString(R.string.handregler_mtm_title));
		alertDialogBuilder.setMessage(getResources().getString(R.string.handregler_mtm_message, selectedTfzNr));
		alertDialogBuilder.setCancelable(false);
		alertDialogBuilder.setView(spinner);
		alertDialogBuilder.setPositiveButton(getResources().getString(R.string.handregler_label_ok), 
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
					executeMtmTfz(spinner.getSelectedItem().toString());
				}
			});
		alertDialogBuilder.setNegativeButton(getResources().getString(R.string.handregler_label_cancel),
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
				}
			});

		AlertDialog alertDialog = alertDialogBuilder.create();
		alertDialog.show();
	}

	private void performMtpTfz() {
		final Spinner spinner = new Spinner(this);
		ArrayAdapter<String> adapter = new ArrayAdapter<String>(
			this, android.R.layout.simple_spinner_item, getTfzArrayForMultitraction(true));
		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		spinner.setAdapter(adapter);

		AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
		alertDialogBuilder.setTitle(getResources().getString(R.string.handregler_mtp_title));
		alertDialogBuilder.setMessage(getResources().getString(R.string.handregler_mtp_message, selectedTfzNr));
		alertDialogBuilder.setCancelable(false);
		alertDialogBuilder.setView(spinner);
		alertDialogBuilder.setPositiveButton(getResources().getString(R.string.handregler_label_ok), 
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
					executeMtpTfz(spinner.getSelectedItem().toString());
				}
			});
		alertDialogBuilder.setNegativeButton(getResources().getString(R.string.handregler_label_cancel),
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
				}
			});

		AlertDialog alertDialog = alertDialogBuilder.create();
		alertDialog.show();
	}

	private void performTermTfz() {
		AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
		alertDialogBuilder.setTitle(getResources().getString(R.string.handregler_term_title));
		alertDialogBuilder.setMessage(getResources().getString(R.string.handregler_term_message, selectedTfzNr));
		alertDialogBuilder.setCancelable(false);
		alertDialogBuilder.setPositiveButton(getResources().getString(R.string.handregler_label_yes), 
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
					executeTermTfz();
				}
			});
		alertDialogBuilder.setNegativeButton(getResources().getString(R.string.handregler_label_no),
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
				}
			});

		AlertDialog alertDialog = alertDialogBuilder.create();
		alertDialog.show();
	}

	private void performUmkTfz() {
		AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
		alertDialogBuilder.setTitle(getResources().getString(R.string.handregler_umk_title));
		alertDialogBuilder.setMessage(getResources().getString(R.string.handregler_umk_message, selectedTfzNr));
		alertDialogBuilder.setCancelable(false);
		alertDialogBuilder.setPositiveButton(getResources().getString(R.string.handregler_label_yes), 
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
					executeUmkTfz();
				}
			});
		alertDialogBuilder.setNegativeButton(getResources().getString(R.string.handregler_label_no),
			new DialogInterface.OnClickListener() {
				public void onClick(DialogInterface dialog, int id) {
					dialog.cancel();
				}
			});

		AlertDialog alertDialog = alertDialogBuilder.create();
		alertDialog.show();
	}

	private void executeChooseTfz() {
		Tfz choosenTfz = null;

		if (selectedTfzNr != null && tfzControlledByApp) {
			if (abvEnabled) {
				executeFunction(selectedTfzInfo.getFuncAbv(), true);
				abvEnabled = false;
			}
			fahrsteuerungAdapter.stop(selectedTfzNr);
		}

		if (TextUtils.isDigitsOnly(tfzSpinner.getSelectedItem().toString())) {
			selectedTfzNr = tfzSpinner.getSelectedItem().toString();
			choosenTfz = fahrsteuerungAdapter.inf(selectedTfzNr).get(0);
			if (choosenTfz.getMode() == MANUAL) {
				selectedTfzMode = MANUAL;
				if (choosenTfz.getHandregler() == 0) {
					fahrsteuerungAdapter.stop(selectedTfzNr);
				} else {
					tfzAufHandregler = true;
					showText(getResources().getString(R.string.handregler_tfzModeHandregler, 
						selectedTfzNr, Integer.toString(choosenTfz.getHandregler())), LENGTH_LONG);
				}
			} else if (choosenTfz.getMode() == MULTITRACTION) {
				selectedTfzMode = MULTITRACTION;
				showText(getResources().getString(R.string.handregler_tfzModeMultitraction, selectedTfzNr), LENGTH_LONG);
			} else {
				selectedTfzMode = AUTO;
				showText(getResources().getString(R.string.handregler_tfzModeAuto, selectedTfzNr), LENGTH_LONG);
			}

			enableButtons(true);
			findTextView(R.id.handregler_chooseTfzLabel).setTextColor(Color.WHITE);
			findTextView(R.id.handregler_chooseTfzLabel).setText(getResources().getString(R.string.handregler_selectedTfz, selectedTfzNr));
			findViewById(R.id.handregler_chooseTfzBtn).setEnabled(false);
			findViewById(R.id.handregler_deleteTfzBtn).setEnabled(true);
			((EditText)findViewById(R.id.handregler_zugnr_box)).setText("");

			selectedTfzInfo = tfzInfoProvider.getTfzInfo(selectedTfzNr);
			selectedTfzFst = -1;
			suppressSpeedChange = true;
			tfzControlledByApp = false;

			prepareSpeedBarAndLabels();
			prepareFunctionButtons();
			speedBar.setProgress(0);
		} else {
			showText(getResources().getString(R.string.handregler_tfzNumberErr), LENGTH_LONG);
		}
	}

	private void executeStopTfz() {
		selectedTfzFst = -1;
		suppressSpeedChange = true;
		tfzControlledByApp = true;
		tfzAufHandregler = false;
		speedBar.setProgress(0);
		fahrsteuerungAdapter.stop(selectedTfzNr);
		if (selectedTfzMode == AUTO) {
			selectedTfzMode = MANUAL;
			enableButtons(true);
		}
	}

	private void executeRichTfz() {
		if (selectedTfzMode == MANUAL) {
			selectedTfzFst = -1;
			suppressSpeedChange = true;
			tfzControlledByApp = true;
			tfzAufHandregler = false;
			speedBar.setProgress(0);
		}
		fahrsteuerungAdapter.rich(selectedTfzNr);
	}

	private void executeEinbuchTfz() {
		String bahnhof = bhfSpinner.getSelectedItem().toString();
		String gleis = gleisSpinner.getSelectedItem().toString();
		String fstTrack = null;
		if (!gleis.startsWith("B")) {
			fstTrack = StaticDataStorage.getInstance().getBahnhofNummer(bahnhof) + "G" + gleis;
		} else {
			fstTrack = StaticDataStorage.getInstance().getBahnhofNummer(bahnhof) + gleis;
		}
		EditText zugNummerInput = (EditText)findViewById(R.id.handregler_zugnr_box);
		String zugNummer = zugNummerInput.getEditableText().toString();
		String errorMessage = null;

		if (!TextUtils.isEmpty(zugNummer) && !zugNummer.matches("\\d{1,6}")) {
			showText(getResources().getString(R.string.handregler_trainNumberErr), LENGTH_LONG);
			return;
		}

		if (abvEnabled) {
			executeFunction(selectedTfzInfo.getFuncAbv(), true);
			abvEnabled = false;
		}
		fahrsteuerungAdapter.stop(selectedTfzNr);
		if (!fahrsteuerungAdapter.auto(selectedTfzNr, fstTrack)) {
			errorMessage = fahrsteuerungAdapter.getLastResponse();
		}
		if (!TextUtils.isEmpty(zugNummer)) {
			if (!fahrsteuerungAdapter.fertig(selectedTfzNr)) {
				errorMessage = fahrsteuerungAdapter.getLastResponse();
			}
			Util.sleep(1500);
			if (!fahrsteuerungAdapter.zn(selectedTfzNr, zugNummer)) {
				errorMessage = fahrsteuerungAdapter.getLastResponse();
			}
			zugNummerInput.setText("");
		}

		selectedTfzFst = -1;
		suppressSpeedChange = true;
		tfzControlledByApp = false;
		tfzAufHandregler = false;
		selectedTfzInfo = null;
		selectedTfzNr = null;
		selectedTfzZn = null;
		speedBar.setProgress(0);

		if (errorMessage == null) {
			showText(getResources().getString(R.string.handregler_einbuchen), LENGTH_SHORT);
		} else {
			showText(errorMessage, LENGTH_LONG);
		}

		enableButtons(false);
		findViewById(R.id.handregler_deleteTfzBtn).setEnabled(false);
		findViewById(R.id.handregler_chooseTfzBtn).setEnabled(true);
		findTextView(R.id.handregler_chooseTfzLabel).setText(getResources().getString(R.string.handregler_chooseTFZ));
	}

	private void executeReloadTfz() {
		suppressTfzChange = true;
		loadAvailableTFZ();
		findViewById(R.id.handregler_zugnr_box).setEnabled(false);
		findViewById(R.id.handregler_chooseTfzBtn).setEnabled(true);
		((EditText)findViewById(R.id.handregler_zugnr_box)).setText("");
		if (selectedTfzNr != null) {
			findTextView(R.id.handregler_chooseTfzLabel).setTextColor(Color.RED);
		}

		showText(getResources().getString(R.string.handregler_tfzReloaded), LENGTH_SHORT);
	}

	private void executeFunction(int function, Boolean activate) {
		if (!fahrsteuerungAdapter.setf(selectedTfzNr, function, activate)) {
			showText(fahrsteuerungAdapter.getLastResponse(), LENGTH_LONG);
		}
	}

	private void executeDeleteTfz() {
		if (selectedTfzNr != null && tfzControlledByApp && selectedTfzMode == MANUAL && !tfzAufHandregler) {
			if (abvEnabled) {
				executeFunction(selectedTfzInfo.getFuncAbv(), true);
				abvEnabled = false;
			}
			fahrsteuerungAdapter.stop(selectedTfzNr);
		}

		selectedTfzFst = -1;
		suppressSpeedChange = true;
		tfzControlledByApp = false;
		tfzAufHandregler = false;
		selectedTfzInfo = null;
		selectedTfzNr = null;
		selectedTfzZn = null;
		speedBar.setProgress(0);

		enableButtons(false);
		findTextView(R.id.handregler_chooseTfzLabel).setTextColor(Color.WHITE);
		findTextView(R.id.handregler_chooseTfzLabel).setText(getResources().getString(R.string.handregler_chooseTFZ));
		findViewById(R.id.handregler_chooseTfzBtn).setEnabled(true);
		findViewById(R.id.handregler_deleteTfzBtn).setEnabled(false);
		((EditText)findViewById(R.id.handregler_zugnr_box)).setText("");
	}

	private void executeInitTfz(String tfz) {
		if (!TextUtils.isEmpty(tfz) && TextUtils.isDigitsOnly(tfz)) {
			if (!fahrsteuerungAdapter.init(tfz)) {
				showText(fahrsteuerungAdapter.getLastResponse(), LENGTH_LONG);
			} else {
				executeReloadTfz();
			}
		} else {
			showText(getResources().getString(R.string.handregler_tfzNumberErr), LENGTH_LONG);
		}
	}

	private void executeZnTfz(String zn) {
		if (!TextUtils.isEmpty(zn) && TextUtils.isDigitsOnly(zn)) {
			if (!fahrsteuerungAdapter.zn(selectedTfzNr, zn)) {
				showText(fahrsteuerungAdapter.getLastResponse(), LENGTH_LONG);
			}
		} else {
			showText(getResources().getString(R.string.handregler_trainNumberErr), LENGTH_LONG);
		}
	}

	private void executeHndrTfz(String regler) {
		if (!TextUtils.isEmpty(regler) && TextUtils.isDigitsOnly(regler)) {
			if (!fahrsteuerungAdapter.hndr(selectedTfzNr, Integer.parseInt(regler))) {
				showText(fahrsteuerungAdapter.getLastResponse(), LENGTH_LONG);
			} else {
				tfzAufHandregler = true;
			}
		} else {
			showText(getResources().getString(R.string.handregler_handReglerNumberErr), LENGTH_LONG);
		}
	}

	private void executeMtmTfz(String slaveTfz) {
		if (!TextUtils.isEmpty(slaveTfz) && TextUtils.isDigitsOnly(slaveTfz)) {
			if (!fahrsteuerungAdapter.removeMT(selectedTfzNr, slaveTfz)) {
				showText(fahrsteuerungAdapter.getLastResponse(), LENGTH_LONG);
			}
		} else {
			showText(getResources().getString(R.string.handregler_tfzNumberErr), LENGTH_LONG);
		}
	}

	private void executeMtpTfz(String slaveTfz) {
		if (!TextUtils.isEmpty(slaveTfz) && TextUtils.isDigitsOnly(slaveTfz)) {
			if (!fahrsteuerungAdapter.addMT(selectedTfzNr, slaveTfz)) {
				showText(fahrsteuerungAdapter.getLastResponse(), LENGTH_LONG);
			}
		} else {
			showText(getResources().getString(R.string.handregler_tfzNumberErr), LENGTH_LONG);
		}
	}

	private void executeBef2Tfz() {
		if (!fahrsteuerungAdapter.bef2(selectedTfzNr)) {
			showText(fahrsteuerungAdapter.getLastResponse(), LENGTH_LONG);
		}
	}

	private void executeHoldTfz() {
		if (!fahrsteuerungAdapter.hold(selectedTfzNr)) {
			showText(fahrsteuerungAdapter.getLastResponse(), LENGTH_LONG);
		}
	}

	private void executeContTfz() {
		if (!fahrsteuerungAdapter.cont(selectedTfzNr)) {
			showText(fahrsteuerungAdapter.getLastResponse(), LENGTH_LONG);
		}
	}

	private void executeWaitTfz() {
		if (!fahrsteuerungAdapter.wait(selectedTfzNr)) {
			showText(fahrsteuerungAdapter.getLastResponse(), LENGTH_LONG);
		}
	}

	private void executeEndwTfz() {
		if (!fahrsteuerungAdapter.endw(selectedTfzNr)) {
			showText(fahrsteuerungAdapter.getLastResponse(), LENGTH_LONG);
		}
	}

	private void executeTermTfz() {
		if (!fahrsteuerungAdapter.term(selectedTfzNr)) {
			showText(fahrsteuerungAdapter.getLastResponse(), LENGTH_LONG);
		} else {
			selectedTfzInfo = null;
			selectedTfzNr = null;
			selectedTfzZn = null;
			executeDeleteTfz();
			executeReloadTfz();
		}
	}

	private void executeUmkTfz() {
		if (!fahrsteuerungAdapter.umk(selectedTfzNr)) {
			showText(fahrsteuerungAdapter.getLastResponse(), LENGTH_LONG);
		}
	}

	private void executeFertigTfz() {
		if (!fahrsteuerungAdapter.fertig(selectedTfzNr)) {
			showText(fahrsteuerungAdapter.getLastResponse(), LENGTH_LONG);
		}
	}

	private void prepareSpeedBarAndLabels() {
		int maxFst = 0;

		if (selectedTfzInfo != null && speedControl) {
			if (role.equals(RESTRICTED) || role.equals(COMMON) || shuntMode) {
				maxFst = TFZ_VMAX_SHUNTING / 5;
			} else {
				maxFst = selectedTfzInfo.getMaxSpeed() <= TFZ_VMAX ? selectedTfzInfo.getMaxSpeed() / 5 : TFZ_VMAX / 5;
			}
			findTextView(R.id.handregler_tfzSpeedLabel).setText(getResources().getString(R.string.handregler_speed));
			findTextView(R.id.handregler_tfzVALabel).setText(getResources().getString(R.string.handregler_tfzVALabelSpeed));
			findTextView(R.id.tfzSeekBarMiddleValue).setText(Integer.toString((maxFst * 5) / 2));
			findTextView(R.id.tfzSeekBarMaxValue).setText(Integer.toString(maxFst * 5));
		} else {
			if (role.equals(RESTRICTED) || role.equals(COMMON) || shuntMode) {
				maxFst = Config.SEEKBAR_FST_MAX;
			} else {
				maxFst = Integer.parseInt(preferences.getString("pref_key_num_fst", ""));
			}
			findTextView(R.id.handregler_tfzSpeedLabel).setText(getResources().getString(R.string.handregler_fst));
			findTextView(R.id.handregler_tfzVALabel).setText(getResources().getString(R.string.handregler_tfzVALabelFst));
			findTextView(R.id.tfzSeekBarMiddleValue).setText(Integer.toString(maxFst / 2));
			findTextView(R.id.tfzSeekBarMaxValue).setText(Integer.toString(maxFst));
		}
		speedBar.setMax(maxFst);
	}

	private void prepareFunctionButtons() {
		if (role.equals(RESTRICTED) || role.equals(COMMON)) {
			if (selectedTfzInfo != null && selectedTfzInfo.getFuncPfeifen() != -1) {
				findFunctionButton(selectedTfzInfo.getFuncPfeifen()).setVisibility(View.VISIBLE);
				setFunctionButtonText(selectedTfzInfo.getFuncPfeifen(), R.string.handregler_zp1);
			} else {
				findFunctionButton(0).setVisibility(View.GONE);
				findFunctionButton(1).setVisibility(View.GONE);
				findFunctionButton(2).setVisibility(View.GONE);
				findFunctionButton(3).setVisibility(View.GONE);
				findFunctionButton(4).setVisibility(View.GONE);
			}
		} else {
			setFunctionButtonText(0, R.string.handregler_f0);
			setFunctionButtonText(1, R.string.handregler_f1);
			setFunctionButtonText(2, R.string.handregler_f2);
			setFunctionButtonText(3, R.string.handregler_f3);
			setFunctionButtonText(4, R.string.handregler_f4);

			if (selectedTfzInfo != null) {
				if (selectedTfzInfo.getFuncPfeifen() != -1) {
					setFunctionButtonText(selectedTfzInfo.getFuncPfeifen(), R.string.handregler_zp1);
				}
				if (selectedTfzInfo.getFuncTueren() != -1) {
					setFunctionButtonText(selectedTfzInfo.getFuncTueren(), R.string.handregler_tuer);
				}
				if (selectedTfzInfo.getFuncAbv() != -1) {
					setFunctionButtonText(selectedTfzInfo.getFuncAbv(), R.string.handregler_abv);
				}
			}
		}
	}
	
	private void enableButtons(boolean val) {
		findViewById(R.id.handregler_stopTfzBtn).setEnabled(val && selectedTfzMode != MULTITRACTION);
		findViewById(R.id.handregler_richTfzBtn).setEnabled(val && selectedTfzMode != MULTITRACTION);
		findViewById(R.id.handregler_buttonF0).setEnabled(val);
		findViewById(R.id.handregler_buttonF1).setEnabled(val);
		findViewById(R.id.handregler_buttonF2).setEnabled(val);
		findViewById(R.id.handregler_buttonF3).setEnabled(val);
		findViewById(R.id.handregler_buttonF4).setEnabled(val);
		findViewById(R.id.handregler_einbuchTfzBtn).setEnabled(val && selectedTfzMode == MANUAL);
		findViewById(R.id.handregler_zugnr_box).setEnabled(val && selectedTfzMode == MANUAL);
		findViewById(R.id.handregler_tfzSeekBar).setEnabled(val && selectedTfzMode == MANUAL);
		bhfSpinner.setEnabled(val && selectedTfzMode == MANUAL);
		gleisSpinner.setEnabled(val && selectedTfzMode == MANUAL);

		if (!findViewById(R.id.handregler_tfzSeekBar).isEnabled()) {
			findTextView(R.id.tfzSeekBarMiddleValue).setText("");
			findTextView(R.id.tfzSeekBarMaxValue).setText("");
		}

		if (!val) {
			setFunctionButtonText(0, R.string.handregler_f0);
			setFunctionButtonText(1, R.string.handregler_f1);
			setFunctionButtonText(2, R.string.handregler_f2);
			setFunctionButtonText(3, R.string.handregler_f3);
			setFunctionButtonText(4, R.string.handregler_f4);
		}
	}

	private void setSpinnerValues(int id, String[] values) {
		Spinner currentSpinner = (Spinner)findViewById(id);
		ArrayAdapter<CharSequence> adapter = 
				new ArrayAdapter<CharSequence>(this, android.R.layout.simple_spinner_item, values);
		adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
		currentSpinner.setAdapter(adapter);
	}

	private TextView findTextView(int id) {
		return (TextView)findViewById(id);
	}

	private ToggleButton findFunctionButton(int index) {
		return (ToggleButton)findViewById(FUNCTION_BUTTONS[index]);
	}

	private void checkFunctionButtonTouchAction(View v, MotionEvent event, int function) {
		if (event.getAction() == MotionEvent.ACTION_DOWN) {
			executeFunction(function, true);
			v.setPressed(true);
		} else if (event.getAction() == MotionEvent.ACTION_UP) {
			executeFunction(function, false);
			v.setPressed(false);
		}
	}

	private void setFunctionButtonText(int index, int resourceId) {
		findFunctionButton(index).setText(getResources().getString(resourceId));
		findFunctionButton(index).setTextOn(getResources().getString(resourceId));
		findFunctionButton(index).setTextOff(getResources().getString(resourceId));
	}

	private void setFunctionButtonColor(int index) {
		findFunctionButton(index).setChecked(selectedTfzNr != null && tfzInfo.getFunction()[index]);
		if (findFunctionButton(index).isEnabled()) {
			if (selectedTfzNr != null && tfzInfo.getFunction()[index]) {
				findFunctionButton(index).setTextColor(Color.GREEN);
			} else {
				findFunctionButton(index).setTextColor(Color.WHITE);
			}
		} else {
			findFunctionButton(index).setTextColor(Color.DKGRAY);
		}
	}

	private void showText(String text, int length) {
		Toast.makeText(this, text, length).show();
	}
}
